package com.yyt.websocketdemo.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

/**
 * @author: yeyangtao
 * @date: 2020/4/9 09:45
 */
@Slf4j
@Controller
@ServerEndpoint("/chat/{username}")
public class ChatServerEndpoint {
    /**
     * 模拟存储   在线用户
     */
    public static final Map<String, Session> USERS_ONLINE = new ConcurrentHashMap<>();

    /**
     * 返回在线人数
     */
    private synchronized int getOnlineCount() {
        return USERS_ONLINE.size()+1;
    }

    @GetMapping("chat-page")
    public String chatPage() {
        return "chat.html";
    }

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(@PathParam("username") String username, Session session) {
        String message = username + "已上线.当前在线人数：" + getOnlineCount();
        log.info(message);
        USERS_ONLINE.put(username, session);
        sendMessageToAll(message);
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(@PathParam("username") String username, Session session) {
        String message = username + "已下线";
        log.info(message);
        USERS_ONLINE.remove(username);
        sendMessageToAll(message);
        try {
            session.close();
        } catch (IOException e) {
            e.printStackTrace();
            log.error(e.getMessage());
        }
    }

    /**
     * 收到客户端消息后触发调用的方法
     *
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, @PathParam("username") String username) {
        message = "[" + username + "]：" + message;
        sendMessageToAll(message);
    }

    /**
     * 在连接发生异常时触发
     */
    @OnError
    public void onError(Throwable error) {
        log.error("连接异常,原因:" + error.getMessage());
    }

    private void sendMessageToAll(String message) {
        USERS_ONLINE.forEach((name, se) -> syncSend(message, se));
    }

    /**
     * 同步发送
     */
    private void syncSend(String message, Session session) {
        try {
            synchronized (this) {
                session.getBasicRemote().sendText(message);
            }
        } catch (IOException e) {
            e.printStackTrace();
            log.error("发送信息失败，原因：" + e.getMessage());
        }
    }

    /**
     * 异步发送
     */
    private void asyncSend(String message, Session session) {
        try {
            synchronized (this) {
                Future<Void> future = session.getAsyncRemote().sendText(message);
                future.get();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
            log.error("线程中断异常");
        } catch (ExecutionException e) {
            e.printStackTrace();
            log.error("执行异常");
        }
    }
}

